#include "util/file_wrapper/file_wrapper.h"

namespace hawking {
namespace indexlib {

ReturnValue<off_t> FslibWrapper::FileLength(const std::string& path) {
    struct stat stat_buf;
    if (0 > ::stat(path.data(), &stat_buf)) {
        return ReturnValue<off_t>{Status::IOError, 0};
    }

    return ReturnValue<off_t>{Status::OK, stat_buf.st_size};
}

// careful use
std::string FslibWrapper::ReadFile(const std::string& path) {
    int32_t fd = open(path.data(), O_RDONLY);
    if (fd == -1) {
        return "";
    }

    struct stat sb;
    if (fstat(fd, &sb) == -1) {
        close(fd);
        return "";
    }

    char* buffer = (char*)mmap(nullptr, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    if (buffer == MAP_FAILED) {
        close(fd);
        return "";
    }

    std::string result(buffer, sb.st_size);
    munmap(buffer, sb.st_size);
    close(fd);
    return result;
}

std::vector<std::string_view> FslibWrapper::SplitString(const std::string& str, char d) {
    std::vector<std::string_view> views;
    size_t pos = 0;
    size_t prev_pos = 0;

    while ((pos = str.find(d, prev_pos)) != std::string_view::npos) {
        views.push_back(str.substr(prev_pos, pos - prev_pos));
        prev_pos = pos + 1;
    }

    views.push_back(str.substr(prev_pos, str.size() - prev_pos));
    return views;
}

bool FslibWrapper::PathExist(const std::string& path) {
    const butil::FilePath butil_path(path);
    return butil::PathExists(butil_path);
}

std::vector<std::string> FslibWrapper::GetSubDir(const std::string& path) {
    std::vector<std::string> sub_dirs;
    DIR *dir = opendir(path.data());
    struct dirent *ent;

    if (dir) {
        while ((ent = readdir(dir)) != nullptr) {
            if (ent->d_type == DT_DIR && ent->d_name[0] != '.') {
                sub_dirs.push_back(ent->d_name);
            }
        }

        closedir(dir);
    }

    return sub_dirs;
}

std::string FslibWrapper::Set2String(const std::set<std::string>& s, char d) {
    std::string result;
    for (const auto& iter : s) {
        result += iter;
        result += d;
    }

    if (!result.empty()) {
        result.pop_back();
    }
    return result;
}

bool FslibWrapper::RmDir(const std::string& dirname) {
    return butil::DeleteFile(butil::FilePath(dirname), true);
}

bool FslibWrapper::Mkdir(const std::string& dirname) {
    return butil::CreateDirectory(butil::FilePath(dirname));
}

void FslibWrapper::GetAllFiles(
    const std::string& dirname, std::vector<std::string>* files) {
    if (!std::experimental::filesystem::exists(dirname) ||
        !std::experimental::filesystem::is_directory(dirname)) {
        return;
    }

    for (const auto& entry :
            std::experimental::filesystem::recursive_directory_iterator(dirname)) {
        if (std::experimental::filesystem::is_regular_file(entry)
            && entry.path().filename().string()[0] != '.') {
            files->emplace_back(entry.path().string());
        }
    }
}

}
}